#include <iostream>
#include <vector>
#include <stack>
#include <cstring>
#include <cstdlib>
using namespace std;
#include "SymTable.h"
#include "Lexer.h"
#include "Parser.h"
#include "EvalExpr.h"

// Evaluate the postfix expressions. 
// It retrieves the postfix expressions corresponding to the expressions parsed successfully by the parser.
bool EvalExpr::evaluate(Parser &parser)
{
	SymTable *symTable = SymTable::getMyInstance();
	int nExprs = parser.getParsedOutputCount(), iExpr = 0;
	bool result = true;
	// initialize the value in the symbol table to zeroes.
	symTable->setCounter(0);
	while (1)
	{
		// generate the next value for the symbols.
		if (-1 == symTable->generate())
			return false;
		result = true;
		for(iExpr = 0; iExpr < nExprs; iExpr++)
		{
			result &= posteval(parser.getParsedOutputAtIndex(iExpr));
			// If result is false, break out and check for the next value.
			if (false == result)
				break;
		}
		// If all the expressions have been evaluated.
		if (iExpr == nExprs)
			return true;
		}
}

// Evaluates the postfix expression named postfix.
bool EvalExpr::posteval(const char *postfix)
{
	stack<int> mystack;
	char *tmp, *p;
	int index = 0;
	SymTable *symTable = SymTable::getMyInstance();
	bool op1, op2, result;

	tmp = new char [strlen(postfix) + 1];
	strcpy (tmp, postfix);
	// tokenize with symbol '.'
	p = strtok (tmp, ".");
	while (p!=NULL)
	{
		// push the identifiers. 
		// they are referenced by the index in the symbol table.
		if (isdigit(*p))
		{
			index = atoi(p);
			mystack.push(symTable->ValueForEntryAtIndex(index));
		}
		else
		{
			// If an operator is found, pop two identifiers and perform the operation.
			op2 = mystack.top();
			mystack.pop();
			if('!' == *p)
				mystack.push(!op2);
			else // binary operator, pop one more and operate
			{
				op1 = mystack.top();
				mystack.pop();
				result = operate(op1, op2, p);
				mystack.push(result);
			}
		}
		p = strtok(NULL,".");
	}
	result = mystack.top();
	mystack.pop();
	return result;
}

// perform binary operation 
bool EvalExpr::operate (bool op1, bool op2, char *p)
{
	if ('&' == *p)
		return (op1 & op2);
	else if ('|' == *p)
		return (op1 | op2);
	else  // implies operator p->q == !p|q
		return ( (!op1) | op2 );
}
